unit GLGUICompositeSkin;

interface

{$I GLScene.inc}

uses
  VectorGeometry,
  GLSGenerics,
  GLSCrossXML,
  GLGUIState,
  GLGUITokens,
  GLGUISkin;

type
  TGLGUICompositeSkin = class;
  TGLGUICompositeElements = Array[0..8] of TGLGUIBasicSkin;

  TGLGUICompositeStateDescriptor = class(TGLGUICustomStateDescriptor)
  private
    FSkin: TGLGUICompositeSkin;
    function GetStateSkin: TGLGUICompositeSkin;
    procedure SetStateSkin(ASkin: TGLGUICompositeSkin);
  public
    constructor Create(AType: String); override;
    procedure Parse; override;
    property StateSkin: TGLGUICompositeSkin read GetStateSkin write SetStateSkin;
  end;

  TGLGUICompositeSkin = class(TGLGUICustomSkin)
  private
    FPartsInfo: TGLGUIParts;
    FParts: TGLGUICompositeElements;
    FBorders: TVector;
    function GetStateDescription(AState: TGLGUIState): TGLGUICompositeStateDescriptor;
    function GetPart(AIndex: Integer): TGLGUIBasicSkin;
    function GetBorders: TVector;
  public
    procedure Parse; override;
    procedure Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False); override;
    procedure AddState(AState: TGLGUICompositeStateDescriptor);

    property StateDescription[AState: TGLGUIState]: TGLGUICompositeStateDescriptor read GetStateDescription;
    property Parts[AIndex: Integer]: TGLGUIBasicSkin read GetPart;
    property Borders: TVector read GetBorders;
  end;

implementation

uses
  GLGUISkinManager, GLGUIUtils;

type
  TGLGUICustomStateDescriptorAccessProvider = class(TGLGUICustomStateDescriptor);

{$IFDEF GLS_COMPILER_2005_UP}{$REGION 'State'}{$ENDIF}

constructor TGLGUICompositeStateDescriptor.Create(AType: String);
begin
  inherited;
  FSkin := TGLGUICompositeSkin.Create;
end;

procedure TGLGUICompositeStateDescriptor.Parse;
var
  vCurentStateElement: GLSXMLNode;
  vTemporarySkin: TGLGUICompositeSkin;
  vStateType: String;
  vStateValue: String;
begin
  if FXMLNode = nil then
    Exit;

  vCurentStateElement := FXMLNode.ChildNodes.Get(0);
  GetXMLAttribute(vCurentStateElement, 'Type', vStateType);
  if vStateType = 'Skin' then
  begin
    GetXMLAttribute(vCurentStateElement, 'Value', vStateValue);
    with GUISkinManager do
      vTemporarySkin := TGLGUICompositeSkin(GetSkinByName(vStateValue));
    if not vTemporarySkin.IsParsed then
      vTemporarySkin.Parse;
    StateSkin.Assign(vTemporarySkin);
    FIsParsed := True;
    Exit;
  end;
  FIsParsed := True;
end;

function TGLGUICompositeStateDescriptor.GetStateSkin: TGLGUICompositeSkin;
begin
  Result := FSkin;
end;

procedure TGLGUICompositeStateDescriptor.SetStateSkin(ASkin: TGLGUICompositeSkin);
begin
  FSkin := ASkin;
end;

{$IFDEF GLS_COMPILER_2005_UP}{$ENDREGION}{$ENDIF}

{$IFDEF GLS_COMPILER_2005_UP}{$REGION 'Skin'}{$ENDIF}

procedure TGLGUICompositeSkin.Parse;
var
  i: Integer;
  vCurentSkinElement: GLSXMLNode;
  vState: TGLGUICompositeStateDescriptor;
  vCurrentPart: TGLGUIPart;
  vType: String;
  vInfo: String;
begin
  if FXMLNode = nil then
    Exit;

  if FStates = nil then
  begin
    FStates := TGLGUIStatesList.Create;
  end
  else
  begin
    for I := 0 to FStates.Count - 1 do
      FStates.Items[i].Free;
      FStates.Clear;
  end;

  GetXMLAttribute(FXMLNode, 'Borders', vInfo);
  FBorders := StringToVector4f(vInfo);

  for i := 0 to FXMLNode.ChildNodes.Count - 1 do
  begin
    vCurentSkinElement := FXMLNode.ChildNodes.Get(i);
    if vCurentSkinElement.LocalName = 'SkinElement' then
    begin
      GetXMLAttribute(vCurentSkinElement, 'Type', vType);
      vCurrentPart := StringToGUIPart(vType);
      FPartsInfo := FPartsInfo + [vCurrentPart];
      FParts[Ord(vCurrentPart)] :=  TGLGUIBasicSkin.Create;
      FParts[Ord(vCurrentPart)].Name := Name + '.Part';
      FParts[Ord(vCurrentPart)].Texture := FTexture;
      GetXMLAttribute(vCurentSkinElement, 'Offset', vInfo);
      FParts[Ord(vCurrentPart)].Offset := StringToVector4f(vInfo);
    end;
    if vCurentSkinElement.LocalName = 'State' then
    begin
     GetXMLAttribute(vCurentSkinElement, 'Type', vType);
     vState := TGLGUICompositeStateDescriptor.Create(vType);
     TGLGUICustomStateDescriptorAccessProvider(vState).FXMLNode := vCurentSkinElement;
     AddState(vState);
    end;
  end;
  FIsParsed := True;
end;

procedure TGLGUICompositeSkin.Assign(const ASkin: TGLGUICustomSkin; const AAssignStates: Boolean = False);
var
  I: Integer;
  vState: TGLGUICompositeStateDescriptor;
  vSkin: TGLGUICompositeSkin;
begin
  inherited Assign(ASkin);
  if ASkin.ClassType = TGLGUICompositeSkin then
  begin
    for I := 0 to 8 do
    begin
      if Assigned(TGLGUICompositeSkin(ASkin).Parts[i]) then
      begin
        FParts[i] := TGLGUIBasicSkin.Create;
        FParts[i].Assign(TGLGUICompositeSkin(ASkin).Parts[i]);
      end;
    end;
    FBorders := TGLGUICompositeSkin(ASkin).Borders;
  end
  else
  if ASkin.ClassType = TGLGUIBasicSkin then
  begin
    FParts[0] := TGLGUIBasicSkin.Create;
    FParts[0].Assign(ASkin);
    FBorders := VectorMake(0,0,0,0);
    if AAssignStates then
    begin
      for I := 0 to Ord(high(TGLGUIState)) do
      begin
        if Assigned(TGLGUIBasicSkin(ASkin).StateDescription[TGLGUIState(i)]) then
        begin
          with TGLGUIBasicSkin(ASkin).StateDescription[TGLGUIState(i)] do
          begin
            vState := TGLGUICompositeStateDescriptor.Create(ToString);
            AddState(vState);
            vSkin := TGLGUICompositeSkin.Create;
            vState.StateSkin.Assign(TGLGUIBasicSkin(StateSkin));
          end;
        end;
      end;
    end;
  end;
end;

procedure TGLGUICompositeSkin.AddState(AState: TGLGUICompositeStateDescriptor);
begin
  AState.StateSkin.Assign(Self);
  if not AState.IsParsed then
    AState.Parse;
  FStates.Add(AState);
end;

function TGLGUICompositeSkin.GetPart(AIndex: Integer): TGLGUIBasicSkin;
begin
  if not (AIndex > 8) then
    Result := FParts[AIndex]
  else
    Result := nil;
end;

function TGLGUICompositeSkin.GetBorders: TVector;
begin
  Result := FBorders;
end;

function TGLGUICompositeSkin.GetStateDescription(AState: TGLGUIState): TGLGUICompositeStateDescriptor;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to FStates.Count - 1 do
    if FStates.Items[i].State = AState then
    begin
      Result := TGLGUICompositeStateDescriptor(FStates.Items[i]);
      Exit;
    end;
end;

{$IFDEF GLS_COMPILER_2005_UP}{$ENDREGION}{$ENDIF}

initialization
  RegisterSkin(TGLGUICompositeSkin);

end.
